// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Diagnostics;
using System.Globalization;

namespace Microsoft.TeamFoundation.Migration.Toolkit
{
    /// <summary>
    /// Pair class.
    /// </summary>
    [DebuggerStepThrough]
    public class Pair<T>
    {
        private T m_left;                                   // Left item
        private T m_right;                                  // Right item

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="left">Left item</param>
        /// <param name="right">Right item</param>
        public Pair(
            T left,
            T right)
        {
            m_left = left;
            m_right = right;
        }

        /// <summary>
        /// Gets the value at the given side.
        /// </summary>
        /// <param name="side">Side</param>
        /// <returns>Value</returns>
        public T this[Side side]
        {
            get { return side == Side.Left ? Left : Right; }
            set
            {
                if (side == Side.Left) Left = value;
                else Right = value;
            }
        }

        public T Left { get { return m_left; } set { m_left = value; } }
        public T Right { get { return m_right; } set { m_right = value; } }

        /// <summary>
        /// Inversion.
        /// </summary>
        /// <param name="p">Original pair</param>
        /// <returns>Inverted pair</returns>
        public static Pair<T> operator !(Pair<T> p)
        {
            return p.LogicalNot();
        }

        /// <summary>
        /// Inverts the pair.
        /// </summary>
        /// <returns>Inverted pair</returns>
        public Pair<T> LogicalNot()
        {
            return new Pair<T>(m_right, m_left);
        }

        /// <summary>
        /// Converts to string.
        /// </summary>
        /// <returns>String</returns>
        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "Left: {0}; Right: {1}", Left, Right);
        }
    }

    /// <summary>
    /// Side definition (left/right)
    /// </summary>
    [DebuggerStepThrough]
    public struct Side
    {
        private bool m_isLeft;                              // True for left side

        private static Side s_left = new Side(true);
        private static Side s_right = new Side(false);

        public static Side Left { get { return s_left; } }
        public static Side Right { get { return s_right; } }

        private Side(bool isLeft)
        {
            m_isLeft = isLeft;
        }

        public static Side operator !(
            Side side)
        {
            return side.LogicalNot();
        }

        public Side LogicalNot()
        {
            return m_isLeft ? s_right : s_left;
        }

        public static bool operator ==(
            Side side1,
            Side side2)
        {
            return side1.Equals(side2);
        }

        public static bool operator !=(
            Side side1,
            Side side2)
        {
            return !side1.Equals(side2);
        }

        public override int GetHashCode()
        {
            return m_isLeft.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Side)) return false;

            return Equals((Side)obj);
        }

        private bool Equals(Side s)
        {
            return m_isLeft == s.m_isLeft;
        }

        public override string ToString()
        {
            return m_isLeft ? "Left" : "Right";
        }
    }
}
